package com.yoso.starter.boot.aspect;

import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson2.JSON;
import com.yoso.core.dto.ResponseResult;
import com.yoso.starter.boot.annotation.LoggingArgs;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Optional;

@Aspect
@Component
@Slf4j(topic = "argsReturnLog")
@Order
public class LoggingAspect {


    @Pointcut("@annotation(com.yoso.starter.boot.annotation.LoggingArgs)")
    private void annotationMethod() {}
    @Pointcut("within(com.yoso..controller..*)")
    private void aspectMethod() {}

    
    @Around("annotationMethod() && aspectMethod()")
    public Object logMethodArgumentsAndReturnValue(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().toString();

        Object[] args = joinPoint.getArgs();
        StringBuilder argStringBuilder = new StringBuilder("[");
        if (args.length == 0) {
            argStringBuilder.append("no_Args");
        } else {
            for (Object arg : args) {
                if (arg != null) {
                    argStringBuilder.append(arg).append(", ");
                } else {
                    argStringBuilder.append("<null>, ");
                }
            }
        }
        argStringBuilder.deleteCharAt(argStringBuilder.length() - 2);
        argStringBuilder.append(']');
        
        try {
            Object result = joinPoint.proceed();

            String printResult = "成功！";
            if (isPrintReturn(joinPoint)) {
                printResult = JSON.toJSONString(result);
            } else if (result instanceof ResponseResult && ((ResponseResult<?>) result).getStatus() != HttpStatus.HTTP_OK) {
                printResult = JSON.toJSONString(result);
            }
            log.info("方法： {}，参数： {}, 调用结果： {}", methodName, argStringBuilder, printResult);
            return result;
        } catch (Exception e) {
            log.error("方法： {}，参数： {}，发生错误：{}", methodName, argStringBuilder, e.getMessage());
            throw e;
        }
    }

    /**
     * 是否打印返回结果
     * @param joinPoint
     * @return boolean
     * @author shizejin
     * @date 2023/12/01 10:50
     */
    @SneakyThrows
    private boolean isPrintReturn(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Class<?> classTarget=joinPoint.getTarget().getClass();
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        Method objMethod =classTarget.getMethod(methodName, parameterTypes);
        LoggingArgs annotation = objMethod.getAnnotation(LoggingArgs.class);
        return annotation.printReturn();
    }
}